#include "Common.h"
#include "../infLib/infLib.h"
#include "FileSystem.h"
#include "DeclManager.h"
#include "CVarSystem.h"
#include "CmdSystem.h"
#include "UserInput.h"

#include "../game/Game.h"
#include "../renderer/RenderSystem.h"
#include "../renderer/RenderWorld.h"
#include "../sys/Sys_local.h"
#include "../bullet/Glue/PHYSystem.h"

inf::CmdArgs com_cmdArgs;

extern CVar    com_showFps;

class CommonLocal: public Common {
public:
    CommonLocal() {

    }

    ~CommonLocal() {

    }

    void    RedirectOnRenderSystem( bool on ) {
        redirectOnRenderSystem = on;
    }

    void    Printf( const char *fmt, ... ) {
        if( !redirectOnRenderSystem ) {
            va_list		argptr;
            char		text[INF_MAX_STRING_CHARS] = {0};

            va_start( argptr, fmt );
            inf::vsnPrintf( text, INF_MAX_STRING_CHARS, fmt, argptr );
            va_end( argptr );
            inf::printf(text);
        }
    }

    void    Error( const char *fmt, ... ) {
        if( !redirectOnRenderSystem ) {
            va_list		argptr;
            char		text[INF_MAX_STRING_CHARS] = "error: ";

            va_start( argptr, fmt );
            inf::vsnPrintf( text+7, INF_MAX_STRING_CHARS - 7, fmt, argptr );
            va_end( argptr );
            inf::printf(text);
        }
    }

    void	Warning( const char *fmt, ... ) {
        if( !redirectOnRenderSystem ) {
            va_list		argptr;
            char		text[INF_MAX_STRING_CHARS] = "warning: ";

            va_start( argptr, fmt );
            inf::vsnPrintf( text+9, INF_MAX_STRING_CHARS - 9, fmt, argptr );
            va_end( argptr );

            inf::printf(text);
        }
    }
    void    FatalError( const char* fmt, ...) {
        if( !redirectOnRenderSystem ) {
            va_list		argptr;
            char		text[INF_MAX_STRING_CHARS];

            va_start( argptr, fmt );
            inf::vsnPrintf( text, INF_MAX_STRING_CHARS, fmt, argptr );
            va_end( argptr );

            sys->MessageBoxChar("fatal_error", text, MB_FATALERROR);
        }
    }

    void    Printf( const wchar_t *fmt, ... ) {
        if( !redirectOnRenderSystem ) {
            va_list		argptr;
            wchar_t		text[INF_MAX_STRING_CHARS] = {0};

            va_start( argptr, fmt );
            inf::vsnPrintf( text, INF_MAX_STRING_CHARS, fmt, argptr );
            va_end( argptr );
            inf::printf(text);
        }
    }

    void    Error( const wchar_t *fmt, ... ) {
        if( !redirectOnRenderSystem ) {
            va_list		argptr;
            wchar_t		text[INF_MAX_STRING_CHARS] = L"error: ";

            va_start( argptr, fmt );
            inf::vsnPrintf( text+7, INF_MAX_STRING_CHARS - 7, fmt, argptr );
            va_end( argptr );
            inf::printf(text);
        }
    }

    void	Warning( const wchar_t *fmt, ... ) {
        if( !redirectOnRenderSystem ) {
            va_list		argptr;
            wchar_t		text[INF_MAX_STRING_CHARS] = L"warning: ";

            va_start( argptr, fmt );
            inf::vsnPrintf( text+9, INF_MAX_STRING_CHARS - 9, fmt, argptr );
            va_end( argptr );

            inf::printf(text);
        }
    }

    void    FatalError( const wchar_t* fmt, ...) {
        if( !redirectOnRenderSystem ) {
            va_list		argptr;
            wchar_t		text[INF_MAX_STRING_CHARS];

            va_start( argptr, fmt );
            inf::vsnPrintf( text, INF_MAX_STRING_CHARS, fmt, argptr );
            va_end( argptr );

            sys->MessageBoxWChar(L"fatal_error", text, MB_FATALERROR);
        }
    }

    void    ParseCommandLine( int argc, const char** argv, const char* cmdLine ) {
        inf::Str    strCmdLine;

        if( !cmdLine ) {
            for( int i=0; i<argc; ++i ) {
                strCmdLine +=inf::Str(" ") + argv[i];
            }
        }else
            strCmdLine = cmdLine;

        com_cmdArgs.TokenizeString( strCmdLine );

    }

    void InitGameConfig() {

        const Decl* configDecl = declManager->FindDeclFrom( "iBallance" );

        configDecl->GetString( "title",     config.title );
        configDecl->GetInt( "clientWidth",  config.clientWidth );
		configDecl->GetInt( "clientHeight", config.clientHeight );
		configDecl->GetInt( "bpp",          config.bpp );
		configDecl->GetInt( "multiSample",  config.multiSample );
		configDecl->GetInt( "refreshRate",  config.refreshRate );
	}

	void    Init( int argc, const char** argv, const char* cmdLine ) {
        inf::sys = ::sys;
        inf::common = ::common;

        inf::init();

        ParseCommandLine( argc, argv, cmdLine );

        cvarSystem->Init();
        cmdSystem->Init();

		phySystem->Init();

		//init physic
        CVar::RegisterStaticVars();

        fileSystem->Init( "./base", false );
        declManager->Init();

        declManager->ParsePath( "/" );

        InitGameConfig();

        RedirectOnRenderSystem( false );

        Sys_CreateWindow( Sys_GetAppName(), common->GetClientWidth(), common->GetClientHeight() );
        RInitParams initParams;
        initParams.width        = config.clientWidth;
        initParams.height       = config.clientHeight;
        initParams.bpp          = config.bpp;
        initParams.multiSample  = config.multiSample;
        initParams._refreshRate = config.refreshRate;

        renderSystem->Init( Sys_GetWndHandle(), initParams, RT_GLES1_1 );
        gameImport_t gameImport;
        gameImport.sys          = ::sys;
        gameImport.declManager  = ::declManager;
        gameImport.fileSystem   = ::fileSystem;
        gameImport.common       = ::common;
        gameImport.cvarSystem   = ::cvarSystem;
        gameImport.cmdSystem    = ::cmdSystem;
        gameImport.renderSystem = ::renderSystem;

        Sys_InitInput();

        gameExport = GetGameAPI( &gameImport );

        gameExport->game->Init();
        gameExport->gameEdit->Init();
    }

    void    Shutdown() {
        gameExport->game->Shutdown();
        gameExport->gameEdit->Shutdown();

        Sys_ShutdownInput();
		phySystem->Shutdown();
        renderSystem->Shutdown();

        declManager->Shutdown();
        fileSystem->Shutdown(false);
        cmdSystem->Shutdown();
        cvarSystem->Shutdown();

        inf::shutdown();
    }

    void    Frame() {
        // input
        UserInput::Keyboard();
        UserInput::Mouse();
        UserInput::CharKeys();
        //UserInput::Acculer();
        UserInput::Finish();

        // gameEdit

        // game
        gameExport->game->RunGame();

        // physics

        RenderWorld* world = renderSystem->GetPrimaryWorld();
        // scene
        if( world )
            world->UpdateScene();

		phySystem->Updata(1);

        // render
        if( world ) {
            renderSystem->BeginFrame( config.clientWidth, config.clientHeight );

            world->RenderScene();

            renderSystem->EndFrame( NULL, NULL );
        }
        renderSystem->PresentFrame();

        // sound
    }
protected:
    gameExport_t* gameExport;

    bool redirectOnRenderSystem;
};

CommonLocal commonStatic;
Common*  common = &commonStatic;